/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
  单版本分布式数据库:
单版本是指数据在本地保存是以单个KV条目为单位的方式保存，对每个Key最多只保存一个条目项，
当数据在本地被用户修改时，不管它是否已经被同步出去，均直接在这个条目上进行修改。同步也以此为基础，
按照它在本地被写入或更改的顺序将当前最新一次修改逐条同步至远端设备。
简单来说单版本分布式数据库是通过键值对(Key、Value)的形式保存数据，只能有一个key不能重复，
当本地key数据被修改的时候会被直接修改，然后将最新的数据再同步出去
*/
/*
     设备协同分布式数据库:
 设备协同分布式数据库建立在单版本分布式数据库之上，对应用程序存入的KV数据中的Key前面拼接了
 本设备的DeviceID标识符，这样能保证每个设备产生的数据严格隔离，底层按照设备的维度管理这些数据，
 设备协同分布式数据库支持以设备的维度查询分布式数据，但是不支持修改远端设备同步过来的数据。
简单来说就是在单版本分布式数据库的key前面拼接上本设备的设备id，保证每个设备的数据库能够区分，
知道是哪个设备添加进去的数据；但是不能修改远端设备同步过来的数据，就是在A设备添加的键值对数据推送到B设备，
B设备只能读取该数据，不能对该数据进行修改
 */
import distributedData from '@ohos.data.distributedData'
import Logger from '../model/Logger'

const STORE_ID: string = 'musicplayer_kvstore'
const TAG: string = 'KvStoreModel'

class KvStoreModel {
  private kvManager: distributedData.KVManager
  private kvStore

  constructor() {
  }

  async createKvStore(callback) {
    if (typeof (this.kvStore) === 'undefined') {
      let config = {
        //调用方的包名
        bundleName: 'ohos.samples.etsdistributedmusicplayer',
        userInfo: { //调用方的用户信息
          userId: '0', //指示要设置的用户id
          userType: 0 ////指示要设置的用户类型。默认值为0，指使用同一帐户登录不同设备的用户
        }
      }
      Logger.info(TAG, 'createKVManager begin')
      this.kvManager = await distributedData.createKVManager(config) //创建一个KVManager对象实例，用于管理数据库对象。
      Logger.info(TAG, `createKVManager success, kvManager`)
      let options = {
        createIfMissing: true,
        encrypt: false,
        backup: false,
        autoSync: true,
        //选择单版本数据库
        kvStoreType: distributedData.KVStoreType.SINGLE_VERSION,
        schema: null,
        securityLevel: 3,
      }
      Logger.info(TAG, 'kvManager.getKVStore begin')
      this.kvStore = await this.kvManager.getKVStore(STORE_ID, options) //指定Options和storeId，创建并获取KVStore数据库。
      Logger.info(TAG, `getKVStore success`)
      callback()
      Logger.info(TAG, 'kvManager.getKVStore end')
      Logger.info(TAG, 'createKVManager end')
    } else {
      callback()
    }
  }

  broadcastMessage(msg) {
    Logger.info(TAG, `broadcastMessage ${msg}`)
    let num = Math.random()
    this.createKvStore(() => {
      this.put(msg, num)
    })
  }

  async put(key, value) {
    Logger.info(TAG, `kvStore.put ${key} = ${value}`)
    await this.kvStore.put(key, value) //插入和更新数据。
    this.kvStore.get(key).then((data) => {
      Logger.info(TAG, `kvStore.get ${key} = ${JSON.stringify(data)}`)
    })
    Logger.info(TAG, `kvStore.put ${key} finished`)
  }

  setOnMessageReceivedListener(msg, callback) {
    Logger.info(TAG, `setOnMessageReceivedListener ${msg}`)
    this.createKvStore(() => {
      Logger.info(TAG, 'kvStore.on(dataChange) begin')
      //订阅指定类型的数据变更通知，此方法为同步方法。(通过订阅分布式数据库所有（本地及远端）数据变化实现数据协同)
      //param1:订阅的事件名，固定为’dataChange’，表示数据变更事件。
      //param2:表示订阅的类型:0  表示订阅本地数据变更;1  表示订阅远端数据变更;2  表示订阅远端和本地数据变更;
      this.kvStore.on('dataChange', 1, (data) => { //data是数据变更时通知的对象，包括数据插入的数据、更新的数据、删除的数据和设备ID。
        Logger.info(TAG, `dataChange, ${JSON.stringify(data)}`)
        Logger.info(TAG, `dataChange insert ${data.insertEntries.length} udpate ${data.updateEntries.length}`)
        for (let i = 0; i < data.insertEntries.length; i++) {
          if (data.insertEntries[i].key === msg) {
            Logger.info(TAG, `insertEntries receive ${msg} ${JSON.stringify(data.insertEntries[i].value)}`)
            callback()
            return
          }
        }
        for (let i = 0; i < data.updateEntries.length; i++) {
          if (data.updateEntries[i].key === msg) {
            Logger.info(TAG, `updateEntries receive ${msg} ${JSON.stringify(data.updateEntries[i].value)}`)
            callback()
            return
          }
        }
      })
      Logger.info(TAG, 'kvStore.on(dataChange) end')
    })
  }
}

export default new KvStoreModel()